import itertools

import networkx as nx

from ..arch import Cluster, Arch


def intra_edge(mdg: nx.DiGraph, cluster: Cluster) -> float:
    res = 0
    for edge in itertools.product(cluster, cluster):
        if edge in mdg.edges:
            attr = mdg.get_edge_data(*edge)
            weight = attr["weight"] if "weight" in attr else 1
            res += weight
    return res


def inter_edge(mdg: nx.DiGraph, cluster: Cluster) -> float:
    res = 0
    for u, v in mdg.edges:
        if u in cluster and v not in cluster or u not in cluster and v in cluster:
            attr = mdg.get_edge_data(u, v)
            weight = attr["weight"] if "weight" in attr else 1
            res += weight
    return res


def cf(mdg: nx.DiGraph, cluster: Cluster) -> float:
    intra = intra_edge(mdg, cluster)
    if intra == 0:
        return 0
    else:
        inter = inter_edge(mdg, cluster)
        return (intra * 2) / (intra * 2 + inter)


def turbo(arch: Arch, mdg: nx.DiGraph) -> float:
    res = 0
    for _, cluster in arch.items():
        res += cf(mdg, cluster)
    return res


def norm_turbo(arch: Arch, mdg: nx.DiGraph) -> float:
    turbo_value = turbo(arch, mdg)
    cluster_num = len(arch)
    return turbo_value / cluster_num

#
# if __name__ == '__main__':
#     g = nx.DiGraph()
#     g.add_edges_from(
#         [("1", "3"), ("2", "3"), ("3", "5"), ("4", "1"), ("4", "5"), ("6", "8"), ("6", "7"), ("8", "5"), ("8", "7")])
#     a = {"a": {"1", "2", "3"}, "b": {"4", "5"}, "c": {"6", "7", "8"}}
#     print(turbo(a, g))
#     print(norm_turbo(a, g))
